package com.common.web.config;


import java.util.Date;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import com.common.api.exception.CommonException;
import com.common.util.GenerateSequenceUtil;
import com.common.util.NetworkUtil;
import com.common.web.api.dto.RequestErrorLogDto;
import com.common.web.api.service.RequestErrorLogService;
import com.common.web.dto.response.RestResponse;
import com.common.web.util.RequestUtil;
import com.common.web.util.WebConstant;

import lombok.extern.slf4j.Slf4j;

/**
 * @author ficus
 * Controller统一异常处理
 */
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @Autowired
	private RequestErrorLogService requestErrorLogService;
	
    public GlobalExceptionHandler() {
    	log.debug("初始化全局异常处理器"+this.getClass().getSimpleName());
	}
    
    @ExceptionHandler(value = CommonException.class)
    @ResponseBody
    public RestResponse commonExceptionHandler(HttpServletRequest req, CommonException e) {
        log.error("CommonException 全局统一异常拦截.", e);
        return RestResponse.success().setResultCode(e.getErrorCode()).setResultMsg(e.getErrorMsg());
    }
    
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public RestResponse jsonExceptionHandler(HttpServletRequest req, Exception e) {
        log.error("Exception 全局统一异常拦截.", e);
        RequestErrorLogDto dto=buildDto(e,req);
		requestErrorLogService.add(dto);
        return RestResponse.failure(e.getMessage());
    }
    
    @ExceptionHandler(value = RuntimeException.class)
    @ResponseBody
    public RestResponse businessExceptionHandler(HttpServletRequest req, RuntimeException ex) throws Exception {
    	ex.printStackTrace();
    	log.error("RuntimeException 异常统一拦截器，用于非统一入口业务异常 ,ErrorCode:{},Message:{}",ex.getLocalizedMessage(),ex.toString());
        RequestErrorLogDto dto=buildDto(ex,req);
		requestErrorLogService.add(dto);
    	RestResponse response=RestResponse.failure(ex.getMessage());
        return response;
    }

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public RestResponse methodArgumentNotValidHandler(HttpServletRequest req, MethodArgumentNotValidException e) {
        log.error("参数校验异常 全局统一异常拦截.", e);
        RequestErrorLogDto dto=buildDto(e,req);
        String errorMessages = e.getBindingResult()
                .getAllErrors().stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(","));
        requestErrorLogService.add(dto);
        return RestResponse.failure(errorMessages);
    }
    
    private RequestErrorLogDto buildDto(Exception e,HttpServletRequest req) {  
    	RequestErrorLogDto dto=new RequestErrorLogDto();
    	dto.setId(GenerateSequenceUtil.generateSequenceNo());
    	dto.setErrorInfo(ExceptionUtils.getStackTrace(e));
    	dto.setErrorLevel(WebConstant.requestErrorCode);
//    	dto.setRequestParam(RequestUtil.getRequestParam(req));
    	dto.setRequestServerIp(NetworkUtil.getLocalhost());
    	dto.setRequestSourceIp(RequestUtil.getRequestIp(req));
    	dto.setRequestTime(new Date());
    	dto.setRequestUrl(RequestUtil.getRequestUrl(req));
    	return dto;
    }
}
